package models

import (
	"errors"
	"sort"
	"sync"
	"time"
)

// CleaningScheduler 保洁调度器
type CleaningScheduler struct {
	cleaningTasks map[int64]*CleaningTask
	cleaners      map[int64]*CleaningStaff
	taskQueue     []*CleaningTask
	mutex         sync.RWMutex
}

// CleaningTask 保洁任务
type CleaningTask struct {
	TaskID        int64              `json:"task_id"`
	VenueID       int64              `json:"venue_id"`
	VenueName     string             `json:"venue_name"`
	Priority      int                `json:"priority"`
	Status        CleaningTaskStatus `json:"status"`
	AssignedTo    int64              `json:"assigned_to"`
	StartTime     int64              `json:"start_time"`
	EndTime       int64              `json:"end_time"`
	Duration      int                `json:"duration"`
	TaskType      CleaningTaskType   `json:"task_type"`
	Requirements  []string           `json:"requirements"`
	Location      string             `json:"location"`
	Notes         string             `json:"notes"`
	CreatedAt     int64              `json:"created_at"`
	UpdatedAt     int64              `json:"updated_at"`
	Dependencies  []int64            `json:"dependencies"`
	ConflictTasks []int64            `json:"conflict_tasks"`
}

// CleaningTaskStatus 保洁任务状态
type CleaningTaskStatus int

const (
	TaskPending CleaningTaskStatus = iota + 1
	TaskAssigned
	TaskInProgress
	TaskCompleted
	TaskCancelled
	TaskDelayed
)

// CleaningTaskType 保洁任务类型
type CleaningTaskType int

const (
	RegularCleaning CleaningTaskType = iota + 1
	DeepCleaning
	EmergencyCleaning
	PostEventCleaning
	Sanitization
)

// CleaningStaff 保洁人员（调度专用）
type CleaningStaff struct {
	StaffID      int64               `json:"staff_id"`
	Name         string              `json:"name"`
	Skills       []string            `json:"skills"`
	Availability []TimeSlot          `json:"availability"`
	CurrentTask  *CleaningTask       `json:"current_task"`
	Workload     int                 `json:"workload"`
	Rating       float64             `json:"rating"`
	Location     string              `json:"location"`
	Status       CleaningStaffStatus `json:"status"`
	ShiftType    string              `json:"shift_type"`
}

// CleaningStaffStatus 保洁人员状态
type CleaningStaffStatus int

const (
	CleaningStaffAvailable CleaningStaffStatus = iota + 1
	CleaningStaffBusy
	CleaningStaffOnBreak
	CleaningStaffOffline
)

// TimeSlot 时间段
type TimeSlot struct {
	Start int64 `json:"start"`
	End   int64 `json:"end"`
}

// SchedulingRequest 调度请求
type SchedulingRequest struct {
	Tasks          []*CleaningTask  `json:"tasks"`
	CleaningStaffs []*CleaningStaff `json:"cleaners"`
	StoreID        int64            `json:"store_id"`
	Strategy       string           `json:"strategy"` // priority, balanced, earliest
}

// SchedulingResult 调度结果
type SchedulingResult struct {
	ScheduledTasks        []*ScheduledTask `json:"scheduled_tasks"`
	UnassignedTasks       []*CleaningTask  `json:"unassigned_tasks"`
	CleaningStaffWorkload map[int64]int    `json:"cleaner_workload"`
	TotalDuration         int              `json:"total_duration"`
	Efficiency            float64          `json:"efficiency"`
}

// ScheduledTask 已调度任务
type ScheduledTask struct {
	CleaningTask
	AssignedCleaningStaff *CleaningStaff `json:"assigned_cleaner"`
	EstimatedStart        int64          `json:"estimated_start"`
	EstimatedEnd          int64          `json:"estimated_end"`
}

// NewCleaningScheduler 创建新的保洁调度器
func NewCleaningScheduler() *CleaningScheduler {
	return &CleaningScheduler{
		cleaningTasks: make(map[int64]*CleaningTask),
		cleaners:      make(map[int64]*CleaningStaff),
		taskQueue:     []*CleaningTask{},
	}
}

// ScheduleCleaningTasks 调度保洁任务
func (cs *CleaningScheduler) ScheduleCleaningTasks(request *SchedulingRequest) (*SchedulingResult, error) {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()

	result := &SchedulingResult{
		ScheduledTasks:        []*ScheduledTask{},
		UnassignedTasks:       []*CleaningTask{},
		CleaningStaffWorkload: make(map[int64]int),
		Efficiency:            0.0,
	}

	// 加载任务和保洁人员
	cs.loadTasksAndCleaningStaffs(request)

	// 计算任务优先级
	cs.calculateTaskPriorities()

	// 排序任务队列
	cs.sortTaskQueue(request.Strategy)

	// 分配任务
	cs.assignTasks(result, request.Strategy)

	// 计算效率和总时长
	cs.calculateMetrics(result)

	return result, nil
}

// loadTasksAndCleaningStaffs 加载任务和保洁人员
func (cs *CleaningScheduler) loadTasksAndCleaningStaffs(request *SchedulingRequest) {
	for _, task := range request.Tasks {
		cs.cleaningTasks[task.TaskID] = task
		cs.taskQueue = append(cs.taskQueue, task)
	}

	for _, cleaner := range request.CleaningStaffs {
		cs.cleaners[cleaner.StaffID] = cleaner
	}
}

// calculateTaskPriorities 计算任务优先级
func (cs *CleaningScheduler) calculateTaskPriorities() {
	now := time.Now().Unix()

	for _, task := range cs.taskQueue {
		priority := 0

		// 基于任务类型的优先级
		switch task.TaskType {
		case EmergencyCleaning:
			priority += 1000
		case PostEventCleaning:
			priority += 500
		case DeepCleaning:
			priority += 200
		case Sanitization:
			priority += 150
		case RegularCleaning:
			priority += 100
		}

		// 基于紧急程度的优先级
		if task.StartTime > 0 && task.StartTime <= now+3600 {
			priority += 300 // 1小时内开始的任务
		} else if task.StartTime > 0 && task.StartTime <= now+7200 {
			priority += 200 // 2小时内开始的任务
		}

		// 基于场地重要性的优先级
		venuePriority := cs.getVenuePriority(task.VenueID)
		priority += venuePriority

		task.Priority = priority
	}
}

// getVenuePriority 获取场地优先级
func (cs *CleaningScheduler) getVenuePriority(venueID int64) int {
	// 这里可以根据场地类型、预订情况等因素计算优先级
	// 简化处理：返回基础优先级
	return 50
}

// sortTaskQueue 排序任务队列
func (cs *CleaningScheduler) sortTaskQueue(strategy string) {
	switch strategy {
	case "priority":
		sort.Slice(cs.taskQueue, func(i, j int) bool {
			return cs.taskQueue[i].Priority > cs.taskQueue[j].Priority
		})
	case "earliest":
		sort.Slice(cs.taskQueue, func(i, j int) bool {
			return cs.taskQueue[i].StartTime < cs.taskQueue[j].StartTime
		})
	case "balanced":
		sort.Slice(cs.taskQueue, func(i, j int) bool {
			// 综合考虑优先级和时间
			scoreI := cs.taskQueue[i].Priority + int(1000000/(cs.taskQueue[i].StartTime+1))
			scoreJ := cs.taskQueue[j].Priority + int(1000000/(cs.taskQueue[j].StartTime+1))
			return scoreI > scoreJ
		})
	default:
		sort.Slice(cs.taskQueue, func(i, j int) bool {
			return cs.taskQueue[i].Priority > cs.taskQueue[j].Priority
		})
	}
}

// assignTasks 分配任务
func (cs *CleaningScheduler) assignTasks(result *SchedulingResult, strategy string) {
	for _, task := range cs.taskQueue {
		assigned := false

		// 寻找合适的保洁人员
		bestCleaningStaff := cs.findBestCleaningStaff(task)
		if bestCleaningStaff != nil {
			scheduledTask := &ScheduledTask{
				CleaningTask:          *task,
				AssignedCleaningStaff: bestCleaningStaff,
				EstimatedStart:        task.StartTime,
				EstimatedEnd:          task.StartTime + int64(task.Duration*60),
			}

			result.ScheduledTasks = append(result.ScheduledTasks, scheduledTask)
			result.CleaningStaffWorkload[bestCleaningStaff.StaffID] += task.Duration
			assigned = true
		}

		if !assigned {
			result.UnassignedTasks = append(result.UnassignedTasks, task)
		}
	}
}

// findBestCleaningStaff 寻找最合适的保洁人员
func (cs *CleaningScheduler) findBestCleaningStaff(task *CleaningTask) *CleaningStaff {
	var bestCleaningStaff *CleaningStaff
	bestScore := 0

	for _, cleaner := range cs.cleaners {
		if !cs.canAssignTask(cleaner, task) {
			continue
		}

		score := cs.calculateCleaningStaffScore(cleaner, task)
		if score > bestScore {
			bestScore = score
			bestCleaningStaff = cleaner
		}
	}

	return bestCleaningStaff
}

// canAssignTask 检查是否可以分配任务
func (cs *CleaningScheduler) canAssignTask(cleaner *CleaningStaff, task *CleaningTask) bool {
	// 检查保洁人员状态
	if cleaner.Status != CleaningStaffAvailable {
		return false
	}

	// 检查技能匹配
	if !cs.hasRequiredSkills(cleaner, task) {
		return false
	}

	// 检查时间可用性
	if !cs.isTimeAvailable(cleaner, task) {
		return false
	}

	// 检查冲突任务
	if cs.hasConflicts(cleaner, task) {
		return false
	}

	return true
}

// hasRequiredSkills 检查技能匹配
func (cs *CleaningScheduler) hasRequiredSkills(cleaner *CleaningStaff, task *CleaningTask) bool {
	requiredSkills := make(map[string]bool)
	for _, skill := range task.Requirements {
		requiredSkills[skill] = true
	}

	if len(requiredSkills) == 0 {
		return true
	}

	cleanerSkills := make(map[string]bool)
	for _, skill := range cleaner.Skills {
		cleanerSkills[skill] = true
	}

	for skill := range requiredSkills {
		if !cleanerSkills[skill] {
			return false
		}
	}

	return true
}

// isTimeAvailable 检查时间可用性
func (cs *CleaningScheduler) isTimeAvailable(cleaner *CleaningStaff, task *CleaningTask) bool {
	taskStart := task.StartTime
	taskEnd := task.StartTime + int64(task.Duration*60)

	// 检查保洁人员的可用时间段
	for _, availability := range cleaner.Availability {
		if taskStart >= availability.Start && taskEnd <= availability.End {
			return true
		}
	}

	return false
}

// hasConflicts 检查任务冲突
func (cs *CleaningScheduler) hasConflicts(cleaner *CleaningStaff, task *CleaningTask) bool {
	// 检查是否有依赖任务未完成
	for _, depID := range task.Dependencies {
		if depTask, exists := cs.cleaningTasks[depID]; exists {
			if depTask.Status != TaskCompleted {
				return true
			}
		}
	}

	// 检查是否有冲突任务
	for _, conflictID := range task.ConflictTasks {
		if conflictTask, exists := cs.cleaningTasks[conflictID]; exists {
			if conflictTask.Status == TaskInProgress || conflictTask.Status == TaskAssigned {
				return true
			}
		}
	}

	return false
}

// calculateCleaningStaffScore 计算保洁人员评分
func (cs *CleaningScheduler) calculateCleaningStaffScore(cleaner *CleaningStaff, task *CleaningTask) int {
	score := 0

	// 技能匹配度
	skillMatch := cs.calculateSkillMatch(cleaner, task)
	score += skillMatch * 100

	// 距离因子
	distanceScore := cs.calculateDistanceScore(cleaner, task)
	score += distanceScore * 50

	// 工作负载平衡
	if cleaner.Workload < 4 { // 小时
		score += (4 - cleaner.Workload) * 20
	}

	// 评分因子
	score += int(cleaner.Rating * 10)

	return score
}

// calculateSkillMatch 计算技能匹配度
func (cs *CleaningScheduler) calculateSkillMatch(cleaner *CleaningStaff, task *CleaningTask) int {
	if len(task.Requirements) == 0 {
		return 10
	}

	matchCount := 0
	cleanerSkills := make(map[string]bool)
	for _, skill := range cleaner.Skills {
		cleanerSkills[skill] = true
	}

	for _, req := range task.Requirements {
		if cleanerSkills[req] {
			matchCount++
		}
	}

	return (matchCount * 10) / len(task.Requirements)
}

// calculateDistanceScore 计算距离评分
func (cs *CleaningScheduler) calculateDistanceScore(cleaner *CleaningStaff, task *CleaningTask) int {
	// 简化处理：基于位置字符串计算距离
	// 实际实现中可以使用地理坐标计算
	if cleaner.Location == task.Location {
		return 10
	}
	return 5
}

// calculateMetrics 计算调度指标
func (cs *CleaningScheduler) calculateMetrics(result *SchedulingResult) {
	totalTasks := len(result.ScheduledTasks) + len(result.UnassignedTasks)
	if totalTasks == 0 {
		return
	}

	// 计算效率（已分配任务占比）
	result.Efficiency = float64(len(result.ScheduledTasks)) / float64(totalTasks)

	// 计算总时长
	maxEndTime := int64(0)
	for _, task := range result.ScheduledTasks {
		if task.EstimatedEnd > maxEndTime {
			maxEndTime = task.EstimatedEnd
		}
	}

	if maxEndTime > 0 {
		result.TotalDuration = int(maxEndTime - time.Now().Unix())
	}
}

// AddCleaningTask 添加保洁任务
func (cs *CleaningScheduler) AddCleaningTask(task *CleaningTask) error {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()

	if task.TaskID <= 0 {
		return errors.New("无效的任务ID")
	}

	if task.VenueID <= 0 {
		return errors.New("无效的场地ID")
	}

	if task.Duration <= 0 {
		return errors.New("任务时长必须大于0")
	}

	if task.StartTime <= 0 {
		task.StartTime = time.Now().Unix()
	}

	task.CreatedAt = time.Now().Unix()
	task.UpdatedAt = time.Now().Unix()
	task.Status = TaskPending

	cs.cleaningTasks[task.TaskID] = task
	cs.taskQueue = append(cs.taskQueue, task)

	return nil
}

// UpdateTaskStatus 更新任务状态
func (cs *CleaningScheduler) UpdateTaskStatus(taskID int64, status CleaningTaskStatus, cleanerID int64) error {
	cs.mutex.Lock()
	defer cs.mutex.Unlock()

	task, exists := cs.cleaningTasks[taskID]
	if !exists {
		return errors.New("任务不存在")
	}

	task.Status = status
	task.AssignedTo = cleanerID
	task.UpdatedAt = time.Now().Unix()

	return nil
}

// GetTaskStatus 获取任务状态
func (cs *CleaningScheduler) GetTaskStatus(taskID int64) (*CleaningTask, error) {
	cs.mutex.RLock()
	defer cs.mutex.RUnlock()

	task, exists := cs.cleaningTasks[taskID]
	if !exists {
		return nil, errors.New("任务不存在")
	}

	return task, nil
}

// GetTasksByStatus 根据状态获取任务
func (cs *CleaningScheduler) GetTasksByStatus(status CleaningTaskStatus) []*CleaningTask {
	cs.mutex.RLock()
	defer cs.mutex.RUnlock()

	var tasks []*CleaningTask
	for _, task := range cs.cleaningTasks {
		if task.Status == status {
			tasks = append(tasks, task)
		}
	}

	return tasks
}

// AutoScheduleCleaningTasks 自动调度保洁任务
func (cs *CleaningScheduler) AutoScheduleCleaningTasks(storeID int64) (*SchedulingResult, error) {
	// 获取待保洁的场地
	pendingCleanings := cs.getPendingCleaningVenues(storeID)

	// 获取可用保洁人员
	availableCleaningStaffs := cs.getAvailableCleaningStaffs(storeID)

	// 创建调度请求
	request := &SchedulingRequest{
		Tasks:          pendingCleanings,
		CleaningStaffs: availableCleaningStaffs,
		StoreID:        storeID,
		Strategy:       "priority",
	}

	return cs.ScheduleCleaningTasks(request)
}

// getPendingCleaningVenues 获取待保洁的场地
func (cs *CleaningScheduler) getPendingCleaningVenues(storeID int64) []*CleaningTask {
	// 这里应该从数据库查询待保洁的场地
	// 简化处理：返回示例数据
	return []*CleaningTask{}
}

// getAvailableCleaningStaffs 获取可用保洁人员
func (cs *CleaningScheduler) getAvailableCleaningStaffs(storeID int64) []*CleaningStaff {
	// 这里应该从数据库查询可用保洁人员
	// 简化处理：返回示例数据
	return []*CleaningStaff{}
}

// GenerateCleaningReport 生成保洁报告
func (cs *CleaningScheduler) GenerateCleaningReport(storeID int64, startDate, endDate int64) (*CleaningReport, error) {
	report := &CleaningReport{
		StoreID:   storeID,
		StartDate: startDate,
		EndDate:   endDate,
		Metrics:   make(map[string]int),
	}

	// 统计任务完成情况
	completedTasks := 0
	totalTasks := 0

	for _, task := range cs.cleaningTasks {
		if task.CreatedAt >= startDate && task.CreatedAt <= endDate {
			totalTasks++
			if task.Status == TaskCompleted {
				completedTasks++
			}
		}
	}

	report.Metrics["total_tasks"] = totalTasks
	report.Metrics["completed_tasks"] = completedTasks
	report.Metrics["pending_tasks"] = totalTasks - completedTasks

	if totalTasks > 0 {
		report.Metrics["completion_rate"] = (completedTasks * 100) / totalTasks
	}

	return report, nil
}

// CleaningReport 保洁报告
type CleaningReport struct {
	StoreID   int64           `json:"store_id"`
	StartDate int64           `json:"start_date"`
	EndDate   int64           `json:"end_date"`
	Metrics   map[string]int  `json:"metrics"`
	Tasks     []*CleaningTask `json:"tasks"`
}
